package service

import (
	"context"
	"errors"
	"go.uber.org/zap"
	"golang.org/x/crypto/bcrypt"
	"webook/internal/domain"
	"webook/internal/repository"
)

var (
	ErrUserDuplicate      = repository.ErrUserDuplicate
	ErrUserEmailNotExists = repository.ErrUserEmailNotExists
	ErrUserPasswordFalse  = errors.New("password false")
)

type IUserService interface {
	SignUp(ctx context.Context, u domain.User) error
	Login(ctx context.Context, user domain.User) (domain.User, error)
	Edit(ctx context.Context, user domain.User) error
	GetUserById(ctx context.Context, id int64) (domain.User, error)
	FindOrCreate(ctx context.Context, phone string) (domain.User, error)
	FindOrCreateByWeChat(ctx context.Context, info domain.WeChatInfo) (domain.User, error)
}

type UserService struct {
	repo repository.UserRepository
}

func NewUserService(repo repository.UserRepository) IUserService {
	return &UserService{
		repo: repo,
	}
}
func (svc *UserService) SignUp(ctx context.Context, u domain.User) error {
	// service 层进行业务加密
	encryptedPwd, err := bcrypt.GenerateFromPassword([]byte(u.Password), bcrypt.DefaultCost)
	if err != nil {
		return err
	}
	u.Password = string(encryptedPwd)
	err = svc.repo.Create(ctx, u)
	if err == ErrUserDuplicate {
		return ErrUserDuplicate
	}
	return err
}

func (svc *UserService) Login(ctx context.Context, user domain.User) (domain.User, error) {
	// 1. 首先根据邮箱查找用户
	dbUser, err := svc.repo.FindByEmail(ctx, user.Email)
	if err == ErrUserEmailNotExists {
		return domain.User{}, ErrUserEmailNotExists
	}
	// 2. 校验密码是否一致
	if err = bcrypt.CompareHashAndPassword([]byte(dbUser.Password), []byte(user.Password)); err != nil {
		return domain.User{}, ErrUserPasswordFalse
	}
	return dbUser, nil
}

func (svc *UserService) Edit(ctx context.Context, user domain.User) error {
	return svc.repo.UpdateById(ctx, user)
}

func (svc *UserService) GetUserById(ctx context.Context, id int64) (domain.User, error) {
	user, err := svc.repo.FindById(ctx, id)
	if err != nil {
		return domain.User{}, err
	}
	return user, nil
}

func (svc *UserService) FindOrCreate(ctx context.Context, phone string) (domain.User, error) {
	// 1. 首先查询用户是否已经存在
	u, err := svc.repo.FindByPhone(ctx, phone)
	// 快路径: 用户已经存在
	if err == nil {
		return u, nil
	}
	// 慢路径: 用户首次登录
	// 2. 创建新用户
	err = svc.repo.Create(ctx, domain.User{
		Phone: phone,
	})
	if err == ErrUserDuplicate {
		return domain.User{}, ErrUserDuplicate
	}
	if err != nil {
		return domain.User{}, err
	}
	// 3. 还是拿不到id，再查一次（存在主从延迟问题）
	u, err = svc.repo.FindByPhone(ctx, phone)
	return u, err
}

func (svc *UserService) FindOrCreateByWeChat(ctx context.Context, weChatInfo domain.WeChatInfo) (domain.User, error) {
	// 1. 首先查询用户是否已经存在
	u, err := svc.repo.FindByWeChat(ctx, weChatInfo)
	// 快路径: 用户已经存在
	if err == nil {
		return u, nil
	}
	// 慢路径: 用户首次登录
	// 记录日志
	zap.L().Info("用户首次使用微信登录，开始注册!",
		zap.Any("wechat_info", weChatInfo))
	// 2. 创建新用户
	err = svc.repo.Create(ctx, domain.User{
		WeChatInfo: weChatInfo,
	})
	if err == ErrUserDuplicate {
		return domain.User{}, ErrUserDuplicate
	}
	if err != nil {
		return domain.User{}, err
	}
	// 3. 还是拿不到id，再查一次（存在主从延迟问题）
	u, err = svc.repo.FindByWeChat(ctx, weChatInfo)
	return u, err
}
